home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / lighting.c < prev    next >
C/C++ Source or Header  |  1998-03-03  |  14KB  |  495 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/lighting.c,v $
  15.  * $Revision: 1.1.1.1 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/03/03 15:12:23 $
  18.  * 
  19.  * Lighting functions.
  20.  * 
  21.  * $Log: lighting.c,v $
  22.  * Revision 1.1.1.1  1998/03/03 15:12:23  nobody
  23.  * reimport after crash from backup
  24.  *
  25.  * Revision 1.1.1.1  1998/02/13  20:20:58  hfrieden
  26.  * Initial Import
  27.  *
  28.  * Revision 2.1  1995/07/24  13:21:56  john
  29.  * Added new lighting calculation code to speed things up.
  30.  * 
  31.  * Revision 2.0  1995/02/27  11:27:33  john
  32.  * New version 2.0, which has no anonymous unions, builds with
  33.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  34.  * 
  35.  * Revision 1.43  1995/02/22  13:57:10  allender
  36.  * remove anonymous union from object structure
  37.  * 
  38.  * Revision 1.42  1995/02/13  20:35:07  john
  39.  * Lintized
  40.  * 
  41.  * Revision 1.41  1995/02/04  21:43:40  matt
  42.  * Changed an assert() to an int3() and deal with the bad case
  43.  * 
  44.  * Revision 1.40  1995/01/15  20:48:27  mike
  45.  * support light field for powerups.
  46.  * 
  47.  * Revision 1.39  1994/12/15  13:04:19  mike
  48.  * Replace Players[Player_num].time_total references with GameTime.
  49.  * 
  50.  * Revision 1.38  1994/11/28  21:50:41  mike
  51.  * optimizations.
  52.  * 
  53.  * Revision 1.37  1994/11/28  01:32:33  mike
  54.  * lighting optimization.
  55.  * 
  56.  * Revision 1.36  1994/11/15  12:01:00  john
  57.  * Changed a bunch of code that uses timer_get_milliseconds to 
  58.  * timer_get_fixed_Seconds.  
  59.  * 
  60.  * Revision 1.35  1994/10/31  21:56:07  matt
  61.  * Fixed bug & added error checking
  62.  * 
  63.  * Revision 1.34  1994/10/21  11:24:57  mike
  64.  * Trap divide overflows in lighting.
  65.  * 
  66.  * Revision 1.33  1994/10/08  14:49:11  matt
  67.  * If viewer changed, don't do smooth lighting hack
  68.  * 
  69.  * Revision 1.32  1994/09/25  23:41:07  matt
  70.  * Changed the object load & save code to read/write the structure fields one
  71.  * at a time (rather than the whole structure at once).  This mean that the
  72.  * object structure can be changed without breaking the load/save functions.
  73.  * As a result of this change, the local_object data can be and has been 
  74.  * incorporated into the object array.  Also, timeleft is now a property 
  75.  * of all objects, and the object structure has been otherwise cleaned up.
  76.  * 
  77.  * Revision 1.31  1994/09/25  15:45:15  matt
  78.  * Added OBJ_LIGHT, a type of object that casts light
  79.  * Added generalized lifeleft, and moved it to local_object
  80.  * 
  81.  * Revision 1.30  1994/09/11  15:48:27  mike
  82.  * Use vm_vec_mag_quick in place of vm_vec_mag in point_dist computation.
  83.  * 
  84.  * Revision 1.29  1994/09/08  21:44:49  matt
  85.  * Made lighting ramp 4x as fast; made only static (ambient) light ramp
  86.  * up, but not headlight & dynamic light
  87.  * 
  88.  * Revision 1.28  1994/09/02  14:00:07  matt
  89.  * Simplified explode_object() & mutliple-stage explosions
  90.  * 
  91.  * Revision 1.27  1994/08/29  19:06:44  mike
  92.  * Make lighting proportional to square of distance, not linear.
  93.  * 
  94.  * Revision 1.26  1994/08/25  18:08:38  matt
  95.  * Made muzzle flash cast 3x as much light
  96.  * 
  97.  * Revision 1.25  1994/08/23  16:38:31  mike
  98.  * Key weapon light off bitmaps.tbl.
  99.  * 
  100.  * Revision 1.24  1994/08/13  12:20:44  john
  101.  * Made the networking uise the Players array.
  102.  * 
  103.  * Revision 1.23  1994/08/12  22:42:18  john
  104.  * Took away Player_stats; added Players array.
  105.  * 
  106.  * Revision 1.22  1994/07/06  10:19:22  matt
  107.  * Changed include
  108.  * 
  109.  * Revision 1.21  1994/06/28  13:20:22  mike
  110.  * Oops, fixed a dumb typo.
  111.  * 
  112.  * Revision 1.20  1994/06/28  12:53:25  mike
  113.  * Change lighting function for flares, make brighter and asynchronously flicker.
  114.  * 
  115.  * Revision 1.19  1994/06/27  18:31:15  mike
  116.  * Add flares.
  117.  * 
  118.  * Revision 1.18  1994/06/20  13:41:17  matt
  119.  * Added time-based gradual lighting hack for objects
  120.  * Took out strobing robots
  121.  * 
  122.  * Revision 1.17  1994/06/19  16:25:54  mike
  123.  * Optimize lighting.
  124.  * 
  125.  * Revision 1.16  1994/06/17  18:08:08  mike
  126.  * Make robots cast more and variable light.
  127.  * 
  128.  * Revision 1.15  1994/06/13  15:15:55  mike
  129.  * Fix phantom light, every 64K milliseconds, muzzle flash would flash again.
  130.  * 
  131.  */
  132.  
  133.  
  134. #pragma off (unreferenced)
  135. static char rcsid[] = "$Id: lighting.c,v 1.1.1.1 1998/03/03 15:12:23 nobody Exp $";
  136. #pragma on (unreferenced)
  137.  
  138. #include <stdlib.h>
  139. #include <string.h>    // for memset()
  140. #include <bsd/bsd.h>
  141.  
  142. #include "inferno.h"
  143. #include "segment.h"
  144. #include "error.h"
  145. #include "mono.h"
  146. #include "render.h"
  147. #include "game.h"
  148. #include "vclip.h"
  149. #include "lighting.h"
  150. #include "3d.h"
  151. #include "laser.h"
  152. #include "timer.h"
  153. #include "player.h"
  154. #include "weapon.h"
  155. #include "powerup.h"
  156.  
  157. //global saying how bright the light beam is
  158. fix    Beam_brightness = (F1_0/2);
  159. // -- optimized out, mk, 11/28/94 -- fix    Face_light_scale = (F1_0/2);
  160. int    use_beam;        //flag for beam effect
  161.  
  162. int    Do_dynamic_light=1;
  163.  
  164. fix    Dynamic_light[MAX_VERTICES];
  165.  
  166. // ----------------------------------------------------------------------------------------------
  167. void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices)
  168. {
  169.     int    vv;
  170.  
  171.     if (obj_intensity) {
  172.         fix    obji_64 = obj_intensity*64;
  173.  
  174.         // for pretty dim sources, only process vertices in object's own segment.
  175.         if (obji_64 <= F1_0*8) {
  176.             short *vp = Segments[obj_seg].verts;
  177.  
  178.             for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) {
  179.                 int            vertnum;
  180.                 vms_vector    *vertpos;
  181.                 fix            dist;
  182.  
  183.                 vertnum = vp[vv];
  184.                 vertpos = &Vertices[vertnum];
  185.                 dist = vm_vec_dist_quick(obj_pos, vertpos);
  186.                 dist = fixmul(dist/4, dist/4);
  187.                 if (dist < obji_64) {
  188.                     if (dist < MIN_LIGHT_DIST)
  189.                         dist = MIN_LIGHT_DIST;
  190.  
  191.                     Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
  192.                 }
  193.             }
  194.         } else {
  195.             for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) {
  196.                 int            vertnum;
  197.                 vms_vector    *vertpos;
  198.                 fix            dist;
  199.  
  200.                 vertnum = render_vertices[vv];
  201.                 vertpos = &Vertices[vertnum];
  202.                 dist = vm_vec_dist_quick(obj_pos, vertpos);
  203.  
  204.                 if (dist < obji_64) {
  205.                     if (dist < MIN_LIGHT_DIST)
  206.                         dist = MIN_LIGHT_DIST;
  207.  
  208.                     Dynamic_light[vertnum] += fixdiv(obj_intensity, dist);
  209.                 }
  210.             }
  211.         }
  212.     }
  213. }
  214.  
  215. #define    FLASH_LEN_FIXED_SECONDS    (F1_0/3)
  216. #define    FLASH_SCALE                    (3*F1_0/FLASH_LEN_FIXED_SECONDS)
  217.  
  218. // ----------------------------------------------------------------------------------------------
  219. void cast_muzzle_flash_light(int n_render_vertices, short *render_vertices)
  220. {
  221.     fix current_time;
  222.     int    i;
  223.     short    time_since_flash;
  224.  
  225.     current_time = timer_get_fixed_seconds();
  226.  
  227.     for (i=0; i<MUZZLE_QUEUE_MAX; i++) {
  228.         if (Muzzle_data[i].create_time) {
  229.             time_since_flash = current_time - Muzzle_data[i].create_time;
  230.             if (time_since_flash < FLASH_LEN_FIXED_SECONDS)
  231.                 apply_light((FLASH_LEN_FIXED_SECONDS - time_since_flash) * FLASH_SCALE, Muzzle_data[i].segnum, &Muzzle_data[i].pos, n_render_vertices, render_vertices);
  232.             else
  233.                 Muzzle_data[i].create_time = 0;        // turn off this muzzle flash
  234.         }
  235.     }
  236. }
  237.  
  238. //    Translation table to make flares flicker at different rates
  239. fix    Obj_light_xlate[16] =
  240.     {0x1234, 0x3321, 0x2468, 0x1735,
  241.      0x0123, 0x19af, 0x3f03, 0x232a,
  242.      0x2123, 0x39af, 0x0f03, 0x132a,
  243.      0x3123, 0x29af, 0x1f03, 0x032a};
  244.  
  245. // ----------------------------------------------------------------------------------------------
  246. void set_dynamic_light(void)
  247. {
  248.     int    objnum,vertnum;
  249.     int    n_render_vertices;
  250.     short    render_vertices[MAX_VERTICES];
  251.     byte    render_vertex_flags[MAX_VERTICES];
  252.     int    render_seg,segnum, v;
  253.  
  254.     if (!Do_dynamic_light)
  255.         return;
  256.  
  257.     memset(render_vertex_flags, 0, Highest_vertex_index+1);
  258.  
  259.     //    Create list of vertices that need to be looked at for setting of ambient light.
  260.     n_render_vertices = 0;
  261.     for (render_seg=0; render_seg<N_render_segs; render_seg++) {
  262.         segnum = Render_list[render_seg];
  263.         if (segnum != -1) {
  264.             short    *vp = Segments[segnum].verts;
  265.             for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
  266.                 int    vnum = vp[v];
  267.                 if (vnum<0 || vnum>Highest_vertex_index) {
  268.                     Int3();        //invalid vertex number
  269.                     continue;    //ignore it, and go on to next one
  270.                 }
  271.                 if (!render_vertex_flags[vnum]) {
  272.                     render_vertex_flags[vnum] = 1;
  273.                     render_vertices[n_render_vertices++] = vnum;
  274.                 }
  275.                 //--old way-- for (s=0; s<n_render_vertices; s++)
  276.                 //--old way--     if (render_vertices[s] == vnum)
  277.                 //--old way--         break;
  278.                 //--old way-- if (s == n_render_vertices)
  279.                 //--old way--     render_vertices[n_render_vertices++] = vnum;
  280.             }
  281.         }
  282.     }
  283.  
  284.     for (vertnum=FrameCount&1; vertnum<n_render_vertices; vertnum+=2) {
  285.         Assert(render_vertices[vertnum]>=0 && render_vertices[vertnum]<=Highest_vertex_index);
  286.         Dynamic_light[render_vertices[vertnum]] = 0;
  287.     }
  288.  
  289.     cast_muzzle_flash_light(n_render_vertices, render_vertices);
  290.  
  291.     //    Note, starting at 1 to skip player, whose light is handled by a different system, of course.
  292. //    for (objnum=1; objnum<=Highest_object_index; objnum++) {
  293.  
  294.     for (render_seg=0; render_seg<N_render_segs; render_seg++) {
  295.         int    segnum = Render_list[render_seg];
  296.  
  297.         objnum = Segments[segnum].objects;
  298.  
  299.         while (objnum != -1) {
  300.             object        *obj = &Objects[objnum];
  301.             vms_vector    *objpos = &obj->pos;
  302.             int            objtype = obj->type;
  303.             fix            obj_intensity;
  304.     
  305.             switch (objtype) {
  306.                 case OBJ_FIREBALL:
  307.                     if (obj->id != 0xff) {
  308.                         if (obj->lifeleft < F1_0*4)
  309.                             obj_intensity = fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value);
  310.                         else
  311.                             obj_intensity = Vclip[obj->id].light_value;
  312.                     } else
  313.                         obj_intensity = 0;
  314.                     break;
  315.                 case OBJ_ROBOT:
  316.                     obj_intensity = F1_0/2;    // + (FrameCount & 0x1f)*F1_0/16;
  317.                     break;
  318.                 case OBJ_WEAPON:
  319.                     obj_intensity = Weapon_info[obj->id].light;
  320.                     if (obj->id == FLARE_ID )
  321.                         obj_intensity = 2* (min(obj_intensity, obj->lifeleft) + ((GameTime ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff));
  322.                     break;
  323.                 case OBJ_POWERUP:
  324.                     obj_intensity = Powerup_info[obj->id].light;
  325.                     break;
  326.                 case OBJ_DEBRIS:
  327.                     obj_intensity = F1_0/4;
  328.                     break;
  329.                 case OBJ_LIGHT:
  330.                     obj_intensity = obj->ctype.light_info.intensity;
  331.                     break;
  332.                 default:
  333.                     obj_intensity = 0;
  334.                     break;
  335.             }
  336.     
  337.             if (obj_intensity)
  338.                 apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices);
  339.  
  340.             objnum = obj->next;
  341.         }
  342.     }
  343.  
  344. }
  345.  
  346. // ---------------------------------------------------------
  347.  
  348. //Compute the lighting from the headlight for a given vertex on a face.
  349. //Takes:
  350. //  point - the 3d coords of the point
  351. //  face_light - a scale factor derived from the surface normal of the face
  352. //If no surface normal effect is wanted, pass F1_0 for face_light
  353. fix compute_headlight_light(vms_vector *point,fix face_light)
  354. {
  355.     fix light;
  356.  
  357.     light = Beam_brightness;
  358.  
  359.     if (light) {                //if no beam, don't bother with the rest of this
  360.         fix point_dist;
  361.  
  362.         if (face_light < 0)
  363.             face_light = 0;
  364.  
  365.         point_dist = vm_vec_mag_quick(point);
  366.  
  367.         //note: beam scale not used if !use_beam
  368.  
  369.         if (point_dist >= MAX_DIST)
  370.  
  371.             light = 0;
  372.  
  373.         else {
  374.             fix dist_scale,temp_lightval;
  375.  
  376.             dist_scale = (MAX_DIST - point_dist) >> MAX_DIST_LOG;
  377.  
  378.             temp_lightval = f1_0/4 + face_light/2;
  379.  
  380.             light = Beam_brightness;
  381.  
  382.             if (use_beam) {
  383.                 fix beam_scale;
  384.  
  385.                 beam_scale = fixdiv(point->z,point_dist);
  386.                 beam_scale = fixmul(beam_scale,beam_scale);    //square it
  387.                 light = fixmul(light,beam_scale);
  388.             }
  389.  
  390.             light = fixmul(light,fixmul(dist_scale,temp_lightval));
  391.  
  392.         }
  393.  
  394.     }
  395.  
  396.     return light;
  397. }
  398.  
  399. //compute the average dynamic light in a segment.  Takes the segment number
  400. fix compute_seg_dynamic_light(int segnum)
  401. {
  402.     fix sum;
  403.     segment *seg;
  404.     short *verts;
  405.  
  406.     seg = &Segments[segnum];
  407.  
  408.     verts = seg->verts;
  409.     sum = 0;
  410.  
  411.     sum += Dynamic_light[*verts++];
  412.     sum += Dynamic_light[*verts++];
  413.     sum += Dynamic_light[*verts++];
  414.     sum += Dynamic_light[*verts++];
  415.     sum += Dynamic_light[*verts++];
  416.     sum += Dynamic_light[*verts++];
  417.     sum += Dynamic_light[*verts++];
  418.     sum += Dynamic_light[*verts];
  419.  
  420.     return sum >> 3;
  421.  
  422. }
  423.  
  424. fix object_light[MAX_OBJECTS];
  425. int object_id[MAX_OBJECTS];
  426. object *old_viewer;
  427.  
  428. #define LIGHT_RATE i2f(4)        //how fast the light ramps up
  429.  
  430. //compute the lighting for an object.  Takes a pointer to the object,
  431. //and possibly a rotated 3d point.  If the point isn't specified, the
  432. //object's center point is rotated.
  433. fix compute_object_light(object *obj,vms_vector *rotated_pnt)
  434. {
  435.     fix light;
  436.     g3s_point objpnt;
  437.     int objnum = obj-Objects;
  438.  
  439.     if (!rotated_pnt) {
  440.         g3_rotate_point(&objpnt,&obj->pos);
  441.         rotated_pnt = &objpnt.p3_vec;
  442.     }
  443.  
  444.     //First, get static light for this segment
  445.  
  446.     light = Segments[obj->segnum].static_light;
  447.  
  448.     //return light;
  449.  
  450.  
  451.     //Now, maybe return different value to smooth transitions
  452.  
  453.     if (Viewer==old_viewer && object_id[objnum] == obj->id) {
  454.         fix delta_light,frame_delta;
  455.  
  456.         delta_light = light - object_light[objnum];
  457.  
  458.         frame_delta = fixmul(LIGHT_RATE,FrameTime);
  459.  
  460.         if (abs(delta_light) <= frame_delta)
  461.  
  462.             object_light[objnum] = light;        //we've hit the goal
  463.  
  464.         else
  465.  
  466.             if (delta_light < 0)
  467.                 light = object_light[objnum] -= frame_delta;
  468.             else
  469.                 light = object_light[objnum] += frame_delta;
  470.  
  471.     }
  472.     else {        //new object, initialize
  473.  
  474.         object_id[objnum] = obj->id;
  475.         object_light[objnum] = light;
  476.     }
  477.  
  478.  
  479.  
  480.     //Next, add in headlight on this object
  481.  
  482.     light += compute_headlight_light(rotated_pnt,f1_0);
  483.  
  484.     //Finally, add in dynamic light for this segment
  485.  
  486.     light += compute_seg_dynamic_light(obj->segnum);
  487.  
  488.  
  489.     old_viewer = Viewer;
  490.  
  491.     return light;
  492. }
  493.  
  494.  
  495.